#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#endif//_WIN32

static void usage(const char *cmd)
{
    printf("Usage: %s [/sysapi] </r|/w|/r+/w+/a/a+> <filepath>\n", cmd);
}

static int inner_sysapi_file(const char *flag, const char *filename)
{
#ifdef _WIN32
#else
    int ret;
    int fd;
    int iflag = 0;
    char buffer[1024] = {0};
    int count;

    if(0 == strcmp(flag, "/r"))
    {
        iflag = O_RDONLY;
    }
    else if(0 == strcmp(flag, "/w"))
    {
        iflag = O_WRONLY | O_TRUNC;
    }
    else if(0 == strcmp(flag, "/r+"))
    {
        iflag = O_RDWR;
    }
    else if(0 == strcmp(flag, "/w+"))
    {
        iflag = O_RDWR | O_CREAT | O_EXCL | O_TRUNC;
    }
    else if(0 == strcmp(flag, "/a"))
    {
        iflag = O_WRONLY | O_APPEND;
    }
    else if(0 == strcmp(flag, "/a+"))
    {
        iflag = O_RDWR | O_APPEND;
    }
    else
    {
        printf("Invalid paramter:%s\n", flag);
        return EINVAL;
    }
    fd = open(filename, iflag, 0);
    if(-1 == fd)
    {
        ret = errno;
        printf("open file failed!ret=%d,filename=%s\n", ret, filename);
        return ret;
    }
    while(true)
    {
        memset(buffer, 0, sizeof(buffer));
        printf(">>");
        fgets(buffer, sizeof(buffer) - 1, stdin);
        if('\0' != buffer[0])
        {
            if(0 == strncmp("read", buffer, sizeof("read") - 1))
            {
                count = atoi(buffer + sizeof("read"));
                if(count > 0)
                {
                    char *tmp = (char *)malloc(count);
                    if(NULL == tmp)
                    {
                        printf("malloc failed!\n");
                        continue;
                    }
                    count = read(fd, tmp, count);
                    if(-1 == count)
                    {
                        ret = errno;
                        printf("read failed!ret=%d\n", ret);
                        free(tmp);
                        continue;
                    }
                    for(int i = 0; i < count; i++)
                    {
                        printf("%02x ", tmp[i]);
                        if (0 == ((i + 1) % 16))
                        {
                            printf("\n");
                        }
                    }
                    printf("\n");
                    free(tmp);
                }
            }
            else if(0 == strncmp("write", buffer, sizeof("write") - 1))
            {
                char *string = buffer + sizeof("write");
                if(-1 == write(fd, string, strlen(string)))
                {
                    ret = errno;
                    printf("write failed!ret=%d\n", ret);
                }
            }
            else if(0 == strncmp("exit", buffer, sizeof("exit") - 1))
            {
                break;
            }
            else
            {
                printf("help    display help message\n");
                printf("read <count>  read count of bytes from file\n");
                printf("write <string>  write string to file\n");
            }
        }
    }
    close(fd);
#endif//_WIN32
    return 0;
}

static int inner_general_file(const char *mode, const char *filename)
{
    int ret;
    FILE *fp;
    char buffer[1024] = {0};
    int count;
    const char *_mode;

    if(0 == strcmp(mode, "/r"))
    {
        _mode = "r";
    }
    else if(0 == strcmp(mode, "/w"))
    {
        _mode = "w";
    }
    else if(0 == strcmp(mode, "/r+"))
    {
        _mode = "r+";
    }
    else if(0 == strcmp(mode, "/w+"))
    {
        _mode = "w+";
    }
    else if(0 == strcmp(mode, "/a"))
    {
        _mode = "a";
    }
    else if(0 == strcmp(mode, "/a+"))
    {
        _mode = "a+";
    }
    else
    {
        printf("Invalid paramter:%s\n", mode);
        return EINVAL;
    }

    fp = fopen(filename, _mode);
    if(NULL == fp)
    {
        ret = errno;
        printf("fopen file failed!ret=%d,filename=%s\n", ret, filename);
        return ret;
    }
    while(true)
    {
        memset(buffer, 0, sizeof(buffer));
        printf(">>");
        fgets(buffer, sizeof(buffer) - 1, stdin);
        if('\0' != buffer[0])
        {
            if(0 == strncmp("read", buffer, sizeof("read") - 1))
            {
                count = atoi(buffer + sizeof("read"));
                if(count > 0)
                {
                    char *tmp = (char *)malloc(count);
                    if(NULL == tmp)
                    {
                        printf("malloc failed!\n");
                        continue;
                    }
                    count = fread(tmp, 1, count, fp);
                    if(-1 == count)
                    {
                        ret = errno;
                        printf("read failed!ret=%d\n", ret);
                        free(tmp);
                        continue;
                    }
                    for(int i = 0; i < count; i++)
                    {
                        printf("%02x ", tmp[i]);
                        if (0 == ((i + 1) % 16))
                        {
                            printf("\n");
                        }
                    }
                    printf("\n");
                    free(tmp);
                }
            }
            else if(0 == strncmp("write", buffer, sizeof("write") - 1))
            {
                char *string = buffer + sizeof("write");
                if((size_t)-1 == fwrite(string, 1, strlen(string), fp))
                {
                    ret = errno;
                    printf("write failed!ret=%d\n", ret);
                }
            }
            else if(0 == strncmp("exit", buffer, sizeof("exit") - 1))
            {
                break;
            }
            else
            {
                printf("help    display help message\n");
                printf("read <count>  read count of bytes from file\n");
                printf("write <string>  write string to file\n");
            }
        }
    }
    fclose(fp);
    return 0;
}

int main(int argc, char **argv)
{
    int ret;

    if(argc < 3)
    {
        usage(argv[0]);
        return EINVAL;
    }
    else if (0 == strcmp(argv[1], "/sysapi"))
    {
        if(argc < 4)
        {
            usage(argv[0]);
            return EINVAL;
        }
        ret = inner_sysapi_file(argv[2], argv[3]);
    }
    else
    {
        ret = inner_general_file(argv[2], argv[3]);
    }
    return ret;
}
